import { Node, Sprite, Color, SpriteFrame } from "cc";
import { BaseMgr } from "../base/BaseMgr";
import ResMgr from "../manager/ResMgr";
import { sp } from "cc";
import { UIOpacity } from "cc";
import { Vec3 } from "cc";
import { v3 } from "cc";
import { isValid } from "cc";

export default class Utils extends BaseMgr {
    static get inst() {
        return this.getInstance();
    }

    getRandomList<T>(randomlist: T[], num: number) {
        const list = [...randomlist];
        let delNum = list.length - num;
        const del = () => {
            if (delNum <= 0) return;
            const delIdx = Math.floor(Math.random() * list.length);
            list.splice(delIdx, 1);
            delNum--;
            if (list.length > 0) {
                del();
            }
        }
        del();
        return list;
    }

    addFlag(flags: number, flag: number) {
        flags = (flags ^ flag) | flag;
        return flags;
    }

    /** 根据权重抽取，isOne为true，则如果weightPool里加起来小于1时，会自动补上剩下空概率 */
    getRandomFromPool(weightPool: number[], isOne = false) {
        let total = 0;
        weightPool.forEach(w => total += w);
        if (isOne) {
            let empty = 1 - total;
            if (empty > 0) {
                weightPool.push(empty);
                total += empty;
            }
        }
        const r = Math.random();
        let index = -1;
        if (total > 0) {
            let wStart = 0;
            for (let i = 0; i < weightPool.length; ++i) {
                const w = weightPool[i] + wStart;
                const rateStart = wStart / total;
                const rate = w / total;
                // console.log("池==", weightPool, r, i, rateStart, rate, total);
                if (r >= rateStart && r < rate) {
                    index = i;
                    break;
                }
                wStart += weightPool[i];
            }
        }
        return index;
    }

    setSpriteFromBundle(path: string, sprite: Sprite | Node, bundleName: string) {
        return this.setSprite(path, sprite, null, null, bundleName);
    }

    setSprite(path: string, sprite: Sprite | Node, colorInLoading?: Color, color?: Color, bundleName?: string): Promise<SpriteFrame> {
        return new Promise(async (resolve, reject) => {
            if (sprite['__path'] == path) {
                return;
            }
            const isInstanceofSprite = sprite instanceof Sprite;
            let sp: Sprite = null;
            if (isInstanceofSprite) {
                sp = sprite;
            } else {
                sp = sprite.getComponent(Sprite)
            }
            sp['__path'] = path;
            if (!colorInLoading)
                colorInLoading = new Color(0, 0, 0, 0)
            sp.color = colorInLoading;
            ResMgr.inst.loadSpriteFrame(path, bundleName).then((spFrame) => {
                sp['__path'] = path;
                sp.spriteFrame = spFrame;
                if (!color)
                    color = new Color(255, 255, 255, 255);
                sp.color = color;
                resolve(spFrame);
            }).catch(() => { sp['__path'] = null; })
        });
    }

    setSpine(path: string, spine: sp.Skeleton, bundleName?: string): Promise<boolean> {
        return new Promise((resolve, reject) => {
            if (!isValid(spine)) return;
            this.getUIOpacity(spine.node).opacity = 0;
            const complete = (isNew: boolean) => {
                if (!isValid(spine)) return;
                this.getUIOpacity(spine.node).opacity = 255;
                spine.node.active = true;
                resolve(isNew);
            }
            if (spine['__path'] == path) {
                complete(false);
                return;
            }
            spine['__path'] = path
            spine.node.active = false;
            ResMgr.inst.loadSpine(path, bundleName).then((skData) => {
                if (spine['__path'] == path) {
                    if (isValid(spine))
                        spine.skeletonData = skData;
                }
                // spine.clearAnimation(0)
                // spine.setToSetupPose();
                complete(true);
            });
        });
    }

    getUIOpacity(node: Node) {
        let uiOpacity = node.getComponent(UIOpacity);
        if (!uiOpacity) {
            uiOpacity = node.addComponent(UIOpacity);
        }
        return uiOpacity;
    }

    getSpinePathParam(pathInfo: string) {
        const param = new SpinePathParam();
        const info = pathInfo.split("|");
        if (info[ESpinePatnParam.Path] && info[ESpinePatnParam.Path].trim())
            param.path = info[0].trim();

        if (info[ESpinePatnParam.AnimName] && info[ESpinePatnParam.AnimName].trim())
            param.animName = info[1].trim();

        if (info[ESpinePatnParam.EffectTimeType] && info[ESpinePatnParam.EffectTimeType].trim())
            param.effectTimeType = Number(info[2].trim());

        if (info[ESpinePatnParam.Loop] && info[ESpinePatnParam.Loop].trim())
            param.loop = !!Number(info[3].trim());

        if (info[ESpinePatnParam.Offset] && info[ESpinePatnParam.Offset].trim()) {
            const offset = JSON.parse(info[4]);
            param.offset = v3(offset[0] || 0, offset[1] || 0);
        }

        if (info[ESpinePatnParam.Scale] && info[ESpinePatnParam.Scale].trim())
            param.scale = Number(info[5].trim());

        if (info[ESpinePatnParam.Delay] && info[ESpinePatnParam.Delay].trim())
            param.delay = Number(info[6].trim());

        if (info[ESpinePatnParam.Rotation] && info[ESpinePatnParam.Rotation].trim())
            param.rotation = Number(info[7].trim());

        if (info[ESpinePatnParam.ZIndex] && info[ESpinePatnParam.ZIndex].trim())
            param.zIndex = Number(info[8].trim());
        return param;
    }

    getTimeDisplay(timeStamp: number) {
        const time = timeStamp / 1000;
        const now = new Date().getTime() / 1000;
        const timeDifference = now - time;
        let displayString = ""
        if (timeDifference < 1800) { // 30分钟内
            displayString = "刚刚";
        } else if (timeDifference < 3600) { // 一小时内
            displayString = "1小时内";
        } else if (timeDifference < 86400) { // 一天内
            const hours: number = Math.floor(timeDifference / 3600);
            displayString = `${hours}小时`;
        } else { // 大于等于一天
            const days: number = Math.floor(timeDifference / 86400);
            displayString = `${days}天前`;
        }
        return displayString;
    }
}

enum ESpinePatnParam {
    Path,
    AnimName,
    EffectTimeType,
    Loop,
    Offset,
    Scale,
    Delay,
    Rotation,
    ZIndex
}

export class SpinePathParam {
    /** spine路径 */
    path = ``;
    /** 动画名称 */
    animName = ``;
    /** 生效类型，0：施法开始执行，1：技能生效开始执行 */
    effectTimeType = 0;
    /** 是否循环 */
    loop = false;
    /** 偏移 */
    offset: Vec3 = v3();
    /** 缩放 */
    scale = 1;
    /** 延迟 */
    delay = 0
    /** 旋转 */
    rotation = 0;
    zIndex = 0
}